texture g_RenderTargetTexture;
texture g_GBufferTexture0;
texture g_GBufferTexture1;
//texture g_GBufferTexture2;
float4 g_GrayscaleParams;
float3 g_PostprocessScale;
float3 g_PostprocessBias;
float2 g_ScreenSize_Inv;
float g_AspectRatio;
float g_TanFovY_Half;
float g_Z_Far;

sampler RenderTargetSampler = sampler_state {
	Texture = (g_RenderTargetTexture);
	AddressU = CLAMP;
	AddressV = CLAMP;
	MinFilter = POINT;
	MagFilter = POINT;
	MipFilter = NONE;
};

sampler GBufferSampler0 = sampler_state {
	Texture = (g_GBufferTexture0);
	AddressU = CLAMP;
	AddressV = CLAMP;
	MinFilter = POINT;
	MagFilter = POINT;
	MipFilter = NONE;
};

sampler GBufferSampler1 = sampler_state {
	Texture = (g_GBufferTexture1);
	AddressU = CLAMP;
	AddressV = CLAMP;
	MinFilter = POINT;
	MagFilter = POINT;
	MipFilter = NONE;
};

/*sampler GBufferSampler2 = sampler_state {
	Texture = (g_GBufferTexture2);
	AddressU = CLAMP;
	AddressV = CLAMP;
	MinFilter = POINT;
	MagFilter = POINT;
	MipFilter = NONE;
};*/

#if FEEDBACK == 1
	texture g_FeedbackTexture;
	float4x4 g_FeedbackTransform;
	float g_FeedbackFactor;
	sampler FeedbackSampler = sampler_state {
		Texture = (g_FeedbackTexture);
		BorderColor = 0;
		AddressU = WRAP;
		AddressV = WRAP;
		MinFilter = LINEAR;
		MagFilter = LINEAR;
		MipFilter = NONE;
	};
#endif

#if PIXELATE == 1
	float2 g_PixelateParam;
#endif

#if COMPONENT_DECOMPOSITION == 1
	// Params of quadratic equation A*y^2 + B*y + C
	float3 g_ComponentDecompositionA;
	float3 g_ComponentDecompositionB;
	float3 g_ComponentDecompositionC;
#endif

#if LOOKUP > 0
	texture g_LookupTexture;
	float4x2 g_LookupTextureTransform;
	int g_LookupFilter;
	int g_LookupMipFilter;
	sampler LookupSampler = sampler_state {
		Texture = (g_LookupTexture);
		AddressU = CLAMP;
		AddressV = CLAMP;
		MinFilter = (g_LookupFilter);
		MagFilter = (g_LookupFilter);
		MipFilter = (g_LookupMipFilter);
	};
#endif

#if VOLUME_LOOKUP != 0
	texture g_VolumeLookupTexture;
	float4x3 g_VolumeLookupTextureTransform;
	int g_VolumeLookupFilter;
	int g_VolumeLookupMipFilter;
	sampler VolumeLookupSampler = sampler_state {
		Texture = (g_VolumeLookupTexture);
		AddressU = WRAP;
		AddressV = WRAP;
		AddressW = CLAMP;
		MinFilter = (g_VolumeLookupFilter);
		MagFilter = (g_VolumeLookupFilter);
		MipFilter = (g_VolumeLookupMipFilter);
	};
#endif

#if DOWNSAMPLING == 1
	float g_DownsamplingFactor;
	#if DITHERING != 0
		texture g_DitheringTexture;
		float2 g_DitheringTextureSize;
		sampler DitheringSampler = sampler_state {
			Texture = (g_DitheringTexture);
			AddressU = WRAP;
			AddressV = WRAP;
			MinFilter = POINT;
			MagFilter = POINT;
			MipFilter = NONE;
		};
	#endif
#endif

#if REFRACTION == 1
	texture g_RefractionTexture;
	float g_RefractionIntensity;
	float4 g_RefractionTexParams;
	sampler RefractionSampler = sampler_state {
		Texture = (g_RefractionTexture);
		AddressU = WRAP;
		AddressV = WRAP;
		MinFilter = LINEAR;
		MagFilter = LINEAR;
		MipFilter = LINEAR;
	};
#endif

#if BLOOM != 0
	texture g_BloomTexture;
	sampler BloomSampler = sampler_state {
		Texture = (g_BloomTexture);
		AddressU = CLAMP;
		AddressV = CLAMP;
		MinFilter = LINEAR;
		MagFilter = LINEAR;
		MipFilter = NONE;
	};
#endif

struct GBUFFER_DATA
{
	float3 Pos_View;
	float3 Normal_View;
	float3 Diffuse;
	float SpecularIntensity;
	float SpecularExponent;
};

void SampleGBuffers_Tex(float2 TexCoord, float3 EyeVec, out GBUFFER_DATA Out)
{
	float4 GBufferSample0 = tex2D(GBufferSampler0, TexCoord);
	float4 GBufferSample1 = tex2D(GBufferSampler1, TexCoord);
	//float4 GBufferSample2 = tex2D(GBufferSampler2, TexCoord);
	
	Out.Pos_View = GBufferSample1.b * EyeVec;
	Out.Normal_View.xy = GBufferSample1.rg * 2 - 1;
	Out.Normal_View.z = -sqrt(1 - Out.Normal_View.x*Out.Normal_View.x - Out.Normal_View.y*Out.Normal_View.y);
	Out.Diffuse = GBufferSample0.rgb;
	Out.SpecularIntensity = GBufferSample0.a;
	Out.SpecularExponent = exp(GBufferSample1.a*10.5);
}

void SampleGBuffers(float2 Pos, float3 EyeVec, out GBUFFER_DATA Out)
{
	float2 TexCoord = (Pos - float2(0.5, 0.5)) * g_ScreenSize_Inv;
	SampleGBuffers_Tex(TexCoord, EyeVec, Out);
}

void PostprocessVS(
	in  float4 In_Pos     : POSITION,
	in  float2 In_Tex     : TEXCOORD0,
	out float4 Out_Pos    : POSITION,
	out float2 Out_Tex    : TEXCOORD0,
	out float3 Out_EyeVec : TEXCOORD1)
{
	Out_Pos = In_Pos;
	Out_Tex = In_Tex;
	Out_EyeVec = float3(
		In_Pos.x * g_TanFovY_Half * g_Z_Far * g_AspectRatio,
		In_Pos.y * g_TanFovY_Half * g_Z_Far,
		g_Z_Far);
}

void PostprocessPS(
	in  float2 Pos    : VPOS,
	in  float2 Tex    : TEXCOORD0,
	in  float3 EyeVec : TEXCOORD1,
	out float4 Out    : COLOR0)
{
	GBUFFER_DATA Data;
	SampleGBuffers(Pos, EyeVec, Data);
	float Depth = Data.Pos_View.z / g_Z_Far;

	#if REFRACTION == 1
		float2 Refraction = tex2D(RefractionSampler, Pos * g_RefractionTexParams.xy + g_RefractionTexParams.zw) * 2 - 1;
		Refraction *= g_RefractionIntensity;
		Tex += Refraction;
	#endif
	
	#if PIXELATE == 1
		Tex = floor(Tex * g_PixelateParam) / g_PixelateParam;
	#endif
	
	#if COMPONENT_DECOMPOSITION == 1
		float3 ComponentBias =
			(g_ComponentDecompositionA*Pos.y + g_ComponentDecompositionB)*Pos.y + g_ComponentDecompositionC;
		float4 RenderTargetSample = tex2D(RenderTargetSampler, Tex + float2(ComponentBias.r, 0));
		RenderTargetSample.g = tex2D(RenderTargetSampler, Tex + float2(ComponentBias.g, 0)).g;
		RenderTargetSample.b = tex2D(RenderTargetSampler, Tex + float2(ComponentBias.b, 0)).b;
		#if BLOOM != 0
			float4 BloomSample = tex2D(BloomSampler, Tex + float2(ComponentBias.r, 0));
			BloomSample.g = tex2D(BloomSampler, Tex + float2(ComponentBias.g, 0)).g;
			BloomSample.b = tex2D(BloomSampler, Tex + float2(ComponentBias.b, 0)).b;
		#endif
	#else
		float4 RenderTargetSample = tex2D(RenderTargetSampler, Tex);
		#if BLOOM != 0
			float4 BloomSample = tex2D(BloomSampler, Tex);
		#endif
	#endif
	
	float4 Color = RenderTargetSample;
	#if BLOOM != 0
		Color += saturate(BloomSample);
	#endif
	
	float Grayscale = dot(Color.rgb, g_GrayscaleParams.xyz);
	Color.rgb = lerp(Color.rgb, float3(Grayscale, Grayscale, Grayscale), g_GrayscaleParams.w);
	
	#if VOLUME_LOOKUP != 0
	{
		float3 tex = float3(Pos-float2(0.5,0.5), Grayscale);
		tex = mul(tex, (float3x3)g_VolumeLookupTextureTransform) + g_VolumeLookupTextureTransform._41_42_43;
		Color.rgb = tex3D(VolumeLookupSampler, tex).rgb;
	}
	#elif LOOKUP != 0
	{
		float2 tex = float2(Grayscale, Depth);
		tex = mul(tex, (float2x2)g_LookupTextureTransform) + g_LookupTextureTransform._41_42;
		Color.rgb = tex2D(LookupSampler, tex).rgb;
	}
	#endif
	
	Color.rgb = Color.rgb * g_PostprocessScale + g_PostprocessBias;

	#if DOWNSAMPLING == 1
	{
		#if DITHERING != 0
		{
			float Bias = tex2D(DitheringSampler, Pos / g_DitheringTextureSize) * 0.99 + 0.005;
			Color.rgb = floor(Color.rgb * g_DownsamplingFactor + Bias) / g_DownsamplingFactor;
		}
		#else
		{
			Color.rgb = floor(Color.rgb * g_DownsamplingFactor + Color.rgb) / g_DownsamplingFactor;
		}
		#endif
	}
	#endif
	
	#if FEEDBACK == 1
		float2 FeedbackTexCoord = mul(float4(Tex.x, Tex.y, 0, 1), g_FeedbackTransform);
		float4 FeedbackSample = tex2D(FeedbackSampler, FeedbackTexCoord);
		Color = lerp(Color, FeedbackSample, g_FeedbackFactor);
	#endif
	
	Out = Color;
}


technique Postprocess {
	pass {
		VertexShader = compile vs_3_0 PostprocessVS();
		PixelShader  = compile ps_3_0 PostprocessPS();
	}
}

